// BackgroundSubstraction.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define MAX_FRAME_DIFFERENCE 30

IplImage* imageStore;
// CvArr* imageStore;
int threshold = 17;
int g_slider_position = 5;
float learningRate = g_slider_position/100.0;


int myThreshold(IplImage* src, IplImage* dest, float threshold, int maxValue )
{
	uchar* origin = (uchar*)src->imageData;
	uchar* destination = (uchar*)dest->imageData;
	uchar* temp = (uchar*)imageStore->imageData;

	for(int i = 0; i < src->height; i++)
	{
		for(int j = 0; j < src->width; j++)
		{
			int v = 0;
			int index = i*src->widthStep + j*src->nChannels;
			for(int k = 0; k < src->nChannels; k++)
				v += origin[index + k ];		

			v = v / (float)src->nChannels;
			if( v < threshold)
			{
				v = 0;
				temp[index] = 0;
			}
			else
			{
				if(temp[index] < MAX_FRAME_DIFFERENCE)
				{
					v = maxValue;	// is foreground
					temp[index]++;
				}
				else
				{
					v = 0;
					temp[index]=0;
				}
			}

			for(int k = 0; k < dest->nChannels; k ++)
				destination[index + k ] = v;
		}
	}

	return 0;
}


void UpdateBackground(IplImage* Iprev, IplImage* Icurrent, IplImage* Iresult,float learning)
{
	int widthStep = Iprev->widthStep;
	int channel = Iprev->nChannels;
	uchar* IprevData = (uchar*)Iprev->imageData;
	uchar* IcurrentData = (uchar*)Icurrent->imageData;
	uchar* IresultData = (uchar*)Iresult->imageData;
	for(int i = 0; i < Iprev->height; i++ )
	{
		for(int j = 0 ; j < Iprev->width; j ++)
		{
			for(int k = 0; k < Iprev->nChannels; k++)
			{
				int index = i*widthStep + j * channel + k;

// 				if(imageStore[index]==0)
// 					IresultData[index] = IprevData[index];
//				else
				
				IresultData[index] =
					learning*IcurrentData[index] + (1-learning)*IprevData[index];
			}
		}
	}
}

void onTrackbarSlide(int pos)
{
	learningRate = g_slider_position / 100.0;
}



int _tmain(int argc, _TCHAR* argv[])
{	
	
	cvNamedWindow("Sample",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("GreyScale",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Subtraction",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("LearningSubstraction",CV_WINDOW_AUTOSIZE);

	CvCapture* capture= cvCreateFileCapture("D:\\Leavy4a_dataset.avi");
	IplImage* Iprev = cvQueryFrame(capture);
	if(!Iprev)
	{
		printf("Error in open file");
		return 0;
	}

	// mark if it is foreground in a long time
	imageStore = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);
	cvZero(imageStore);
	
	cvCreateTrackbar("Threshold","Subtraction",&threshold,40,NULL);
	cvCreateTrackbar("Learning Rate","LearningSubstraction",&g_slider_position,100,onTrackbarSlide);

	
	IplImage* IprevGrey = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);
	cvCvtColor(Iprev,IprevGrey,CV_RGB2GRAY);
	cvShowImage("Sample",Iprev);
	cvShowImage("GreyScale",IprevGrey);
	
	int fps = cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
	printf("Frame-per-second is %d\n",fps);


	IplImage* Icurrent;
	IplImage* Iprev2 = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,3);
	cvCopyImage(Iprev,Iprev2);
	IplImage* IcurrentGrey = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);
	

	while(1)
	{
		//////////////////////////////////////////////////////////////////////////
		// BASIC SUBTRACTION
		//////////////////////////////////////////////////////////////////////////
		Icurrent = cvQueryFrame(capture);
		cvCvtColor(Icurrent,IcurrentGrey,CV_RGB2GRAY);

		IplImage* IFrameForeground = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);

		cvAbsDiff(IcurrentGrey,IprevGrey,IFrameForeground);
//		cvThreshold(IFrameForeground,IFrameForeground,threshold,255,CV_THRESH_BINARY);
		myThreshold(IFrameForeground,IFrameForeground,threshold,255);
		if(!Icurrent)
			break;

		cvShowImage("Sample",Icurrent);
		cvShowImage("GreyScale",IcurrentGrey);
		cvShowImage("Subtraction",IFrameForeground);
		cvCopyImage(IcurrentGrey,IprevGrey);


		//////////////////////////////////////////////////////////////////////////
		// BASIC SUBTRACTION WITH LEARNING
		//////////////////////////////////////////////////////////////////////////
		IplImage* IFrameForeGround2 = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);
		IplImage* Icurrent2 = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,3);
		cvCopyImage(Icurrent,Icurrent2);

		IplImage* IcurrentGrey2 = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);
		IplImage* IprevGrey2 = cvCreateImage(cvSize(Iprev->width,Iprev->height),Iprev->depth,1);

		cvCvtColor(Icurrent2,IcurrentGrey2,CV_RGB2GRAY);
		cvCvtColor(Iprev2,IprevGrey2,CV_RGB2GRAY);
 		cvAbsDiff(IcurrentGrey2,IprevGrey2,IFrameForeGround2); 		
 		cvThreshold(IFrameForeGround2,IFrameForeGround2,threshold,255,CV_THRESH_BINARY);
 		cvShowImage("LearningSubstraction",IFrameForeGround2);
		UpdateBackground(Iprev2,Icurrent2,Iprev2,learningRate);


		char c = cvWaitKey(fps);
		if(c == 27)
			break;
	}

	cvReleaseImage(&IprevGrey);
	cvReleaseCapture(&capture);
	cvDestroyWindow("Sample");
	cvDestroyWindow("GreyScale");
	cvDestroyWindow("Subtraction");

	return 1;
}

